home *** CD-ROM | disk | FTP | other *** search
/ Programming Sound Cards / Programming Sound Cards.iso / sound_56 / dmastep1.asm < prev    next >
Assembly Source File  |  1995-01-01  |  14KB  |  361 lines

  1. ;══════════════════════════════════════════════════════════════════════════════
  2. ; Play 8bit DMA mode for SoundBlaster v1.00
  3. ;   André Baresel (with some help from Craig Jackson)
  4. ;──────────────────────────────────────────────────────────────────────────────
  5. ; STATUS: DOES WORK ON SB16/SBPRO2/SB2.0, TESTPHASE ON SB1.0
  6. ;──────────────────────────────────────────────────────────────────────────────
  7. ; Requirements: 80286, SoundBlaster (see BASEADDR,DMA channel,IRQ number)
  8. ; Resolutions : 8-bit / 4..23khz (no highspeed - but on SB16 4..44kHz)
  9. ; Parameters  : none
  10. ; Notes:
  11. ;  ■ To creat a 8 bit mono unsigned file do :   "VOC2RAW TEST1.VOC /I"
  12. ;
  13. ; ■ DSP command 14h  ... play 8bit mono no autoinit
  14. ; ■ DSP command 40h  ... set sample rate
  15. ; ■ DSP command D1h  ... Enable Speaker
  16. ; ■ DSP command D3h  ... Disable Speaker
  17. ;
  18.  
  19. .MODEL SMALL
  20. .286
  21.  
  22. ; CONSTANTS ───────────────────────────────────────────────────────────────────
  23.  
  24. ; SoundBlaster SETUP
  25. BASEADDR           EQU 0220h       ;SoundBlaster base address
  26. IRQ7               EQU 15          ;SoundBlaster IRQ
  27. DMAchannel         EQU 1           ;SoundBlaster DMA channel
  28.  
  29. ; PIC MASKS FOR MASK/DEMASK IRQ
  30. PICANDMASK         EQU 01111111b   ;'AND' PIC mask for clear IRQ7
  31. PICORMASK          EQU 10000000b   ;'OR' PIC mask for set IRQ7
  32.  
  33. ; DMA CONTROLLER REGISTERS :
  34. WRITEMASK          EQU 00ah         ;WRITE MASK REGISTER
  35. WRITEMODE          EQU 00bh         ;WRITE MODE REGISTER
  36. CLEARFLIPFLOP      EQU 00ch
  37. PAGE_CHN           EQU 083h         ;PAGE REGISTER FOR DMAchannel 1
  38. BASE_CHN           EQU 002h         ;BASEADDRESS REGISTER DMA 1
  39. COUNT_CHN          EQU 003h         ;COUNT REGISTER DMAchannel 1
  40.  
  41. ; SAMPLERATE : (if you change it pay attention to maximum samplerate)
  42. TIMECONST          EQU 165          ; = 10989 Hz (256-1000000/11000)
  43.  
  44. ; DMA WRITE MODE
  45. WANTEDMODE         EQU 01001000b    ; singlemode, nonautoinit, readmode
  46.  
  47. ;──────────────────────────────────────────────────────────────────────────────
  48. ; MACRO DEFINITIONs
  49. ;──────────────────────────────────────────────────────────────────────────────
  50. STARTUP                 MACRO
  51. ; MASM 5.x COMPATIBILITY
  52. __start:                mov     ax,DGROUP
  53.                         mov     ds,ax
  54.                         mov     bx,ss
  55.                         sub     bx,ax
  56.                         shl     bx,004h
  57.                         mov     ss,ax
  58.                         add     sp,bx
  59. ENDM
  60.  
  61. WAITWRITE               MACRO
  62. LOCAL                   loopWait,endloop
  63. ;          Arguments : DX = Status port (BASEADDR+0Ch)
  64. ;          Returns   : n/a
  65. ;          Destroys  : AL
  66.  
  67.                         push    cx
  68.                         xor     cx,cx           ; need that for slow SBs !
  69. loopWait:               dec     cx
  70.                         jz      endloop
  71.                         in      al,dx           ; AL = WRITE COMMAND STATUS
  72.                         or      al,al
  73.                         js      loopWait        ; Jump if bit7=1 - writing not allowed
  74. endloop:                pop     cx
  75. ENDM
  76.  
  77. WAITREAD                MACRO
  78. LOCAL                   loopWait,endloop
  79. ;          Arguments : DX = Status port   (normaly BASEADDR+0Eh)
  80. ;          Returns   : n/a
  81. ;          Destroys  : AL
  82.  
  83.                         push    cx
  84.                         xor     cx,cx           ; need that for slow SBs !
  85. loopWait:               dec     cx
  86.                         jz      endloop
  87.                         in      al,dx           ; AL = DATA AVAILABLE STATUS
  88.                         or      al,al
  89.                         jns     loopWait        ; Jump if bit7=0 - no data available
  90. endloop:                pop     cx
  91. ENDM
  92.  
  93. RESET_DSP               MACRO
  94. local                   SBthere
  95. ;          Arguments : n/a
  96. ;          Returns   : n/a
  97. ;          Destroys  : DX,AL
  98.  
  99.                         mov      dx,BASEADDR+06h
  100.                         mov      al,1
  101.                         out      dx,al          ; start DSP reset
  102.  
  103.                         in       al,dx
  104.                         in       al,dx
  105.                         in       al,dx
  106.                         in       al,dx          ; wait 3 µsec
  107.  
  108.                         xor      al,al
  109.                         out      dx,al          ; end DSP Reset
  110.  
  111.                         add      dx,08h         ; dx = DSP DATA AVAILABLE
  112.                         WAITREAD
  113.                         sub      dx,4           ; dx = DSP Read Data
  114.                         in       al,dx
  115.                         cmp      al,0aah        ; if there is a SB then it returns 0AAh
  116.                         je       SBthere
  117.                         jmp      RESET_ERROR    ; No SB - exit program
  118. SBthere:
  119. ENDM
  120. ;─── End of Macrodefinitions ──────────────────────────────────────────────────
  121.  
  122. .STACK 100h
  123.  
  124. .DATA
  125. ;──────────────────────────────────────────────────────────────────────────────
  126. ; TWO COPIES FOR PAGE OVERRIDE REASONS :
  127.  
  128. SAMPLEBUFFER LABEL BYTE
  129.     INCLUDE TEST1.INC        ; FIRST COPY OF SAMPLE SOUND
  130. SAMPLEBUFFEREND LABEL BYTE
  131.     INCLUDE TEST1.INC        ; SECOND COPY OF SAMPLE SOUND
  132.  
  133.     ready               db 0
  134.  
  135.     information         db 13,10,'DMASTEP1.EXE - play a 8bit mono sample one time'
  136.                         db 13,10,'         (use normal speed and nonautoinit DMA)'
  137.                         db 13,10,'stop playing with any key ...','$'
  138.  
  139.     sberror             db 13,10,'No SoundBlaster at this BASEADDR ! PROGRAM HALTED.','$'
  140.  
  141.     oldInterruptSEG     dw 0
  142.     oldInterruptOFS     dw 0
  143.  
  144.     SAMPLEBUFFERLENGTH = offset SAMPLEBUFFEREND - offset SAMPLEBUFFER
  145. ;──────────────────────────────────────────────────────────────────────────────
  146. .CODE
  147.  STARTUP
  148.  
  149.            RESET_DSP
  150.  
  151.            ; WRITE INFORMATION TO SCREEN :
  152.            mov     dx,offset information
  153.            mov     ah,9
  154.            int     21h                         ; write program information to screen
  155.  
  156.            ; ENABLE SB SPEAKERS (for all SBs <SB16)
  157.            mov     dx,BASEADDR+00Ch            ;DX = DSP Write Data or Command
  158.            WAITWRITE
  159.            mov     al,0D1h                     ; AL = Enable speaker
  160.            out     dx,al                       ; Output: DSP Write Data or Command
  161.  
  162.            ; SETUP IRQ :
  163.            xor     ax,ax
  164.            mov     es,ax                       ; es to page 0 (Interrupt table)
  165.            mov     si,IRQ7*4                   ; si = position in interrupt table
  166.  
  167.            ; DISABLE IRQ
  168.            in      al,021h
  169.            and     al,PICANDMASK               ; SET MASK REGISTER BIT TO DISABLE INTERRUPT
  170.            out     021h,al
  171.  
  172.            ; CHANGE POINTER IN INTERRUPT TABLE
  173.            mov     ax,es:[si]
  174.            mov     [OLDInterruptOFS],ax        ; save offset of old interupt vector for restoring
  175.            mov     ax,OFFSET OWN_IRQ
  176.            mov     es:[si],ax                  ; set offset of new interrupt routine
  177.            mov     ax,es:[si+2]
  178.            mov     [OLDInterruptSEG],ax        ; save segment of old interupt vector for restoring
  179.            mov     ax,cs
  180.            mov     es:[si+2],ax                ; set segment of new interrupt routine
  181.  
  182.            ; CHANGE PIC MASK :
  183.            in      al,021h
  184.            and     al,PICANDMASK   ; CLEAR MASK REGISTER BIT TO ENABLE INTERRUPT
  185.            out     021h,al
  186.  
  187. ;──────────────────────────────────────────────────────────────────────────────
  188. ; calculate page and offset for DMAcontroller :
  189. ;
  190. ; segment*16+offset - 20bit memory location -> upper 4 bits  = page
  191. ;                                              lower 16 bits = offset
  192. ;──────────────────────────────────────────────────────────────────────────────
  193.            mov     si,offset samplebuffer
  194.            mov     cx,SAMPLEBUFFERLENGTH-1
  195.  
  196.            mov     ax,ds
  197.            rol     ax,4                ; * 16 - higher 4 bits in al
  198.            mov     bl,al
  199.            and     bl,00fh             ; BL - higher 4 bits
  200.            and     al,0f0h             ; clear higher 4bits in AL
  201.            add     si,ax               ; SI = offset
  202.            adc     bl,0                ; BL = page
  203. ;──────────────────────────────────────────────────────────────────────────────
  204. ; check for DMApage override :
  205. ; ... problem: DMA controller separates memory into 64KB pages, you can only
  206. ; transfer data is placed in one page - no page overrides are allowed
  207. ;──────────────────────────────────────────────────────────────────────────────
  208. ; To solve that :
  209. ; creat a DMA buffer with double size you want - if the first part is placed
  210. ; on a page border the second part is for sure not
  211. ;──────────────────────────────────────────────────────────────────────────────
  212.            neg     si          ; si = 65536 - si   (bytes left to DMA page border)
  213.            cmp     si,cx       ; if si (bytes left to border) > cx (bytes to play)
  214.            ja      nooverride  ; then there's no page override
  215.  
  216.            ; WE HAVE TO USE SECOND PART
  217.            neg     si          ; si = offset of first part
  218.            add     si,cx       ; si = si + length of one part
  219.            inc     si          ; si=si+1 - start of second part
  220.            inc     bl          ; second part is then on the next page
  221.            neg     si          ; look at the next command ;)
  222.                                ; (that is better than a jump ?)
  223. nooverride:
  224.            neg     si
  225.  
  226. ;──────────────────────────────────────────────────────────────────────────────
  227. ; Setup DMA-controller :
  228. ;
  229. ; 1st  MASK DMA CHANNEL
  230. ;
  231.            mov     al,DMAchannel
  232.            add     al,4
  233.            out     WRITEMASK,al
  234. ;──────────────────────────────────────────────────────────────────────────────
  235. ; 2nd  CLEAR FLIPFLOP
  236. ;
  237.            out     CLEARFLIPFLOP,al
  238. ;──────────────────────────────────────────────────────────────────────────────
  239. ; 3rd  WRITE TRANSFER MODE
  240. ;
  241.            mov     al,WANTEDMODE
  242.            add     al,DMAchannel
  243.            out     WRITEMODE,al
  244. ;──────────────────────────────────────────────────────────────────────────────
  245. ; 4th  WRITE PAGE NUMBER
  246. ;
  247.            mov     al,bl
  248.            out     PAGE_CHN,al
  249. ;──────────────────────────────────────────────────────────────────────────────
  250. ; 5th  WRITE BASEADDRESS
  251. ;
  252.            mov     ax,si
  253.            out     BASE_CHN,al
  254.            mov     al,ah
  255.            out     BASE_CHN,al
  256. ;──────────────────────────────────────────────────────────────────────────────
  257. ; 6th  WRITE SAMPLELENGTH-1
  258. ;
  259.            mov     al,cl
  260.            out     COUNT_CHN,al
  261.            mov     al,ch
  262.            out     COUNT_CHN,al
  263. ;──────────────────────────────────────────────────────────────────────────────
  264. ; 7th  DEMASK CHANNEL
  265. ;
  266.            mov     al,DMAchannel
  267.            out     WRITEMASK,al
  268.  
  269. ;──────────────────────────────────────────────────────────────────────────────
  270. ; Setup SoundBlaster :
  271. ;
  272. ; 1st  SET TIMECONSTANTE
  273. ;
  274.            mov     dx,BASEADDR+00Ch            ;DX = DSP Write Data or Command
  275.            WAITWRITE
  276.            mov     al,040h                     ;AL = Set timeconstant
  277.            out     dx,al
  278.            WAITWRITE
  279.            mov     al,TIMECONST
  280.            out     dx,al
  281. ;──────────────────────────────────────────────────────────────────────────────
  282. ; 2nd  use 8bit mono nonautoinit (DSPcommand 014h XXXXh)
  283. ;
  284.            WAITWRITE
  285.            mov     al,014h                     ;AL = DMA DAC 8bit
  286.            out     dx,al
  287.            mov     cx,SAMPLEBUFFERLENGTH-1
  288.            WAITWRITE
  289.            mov     al,cl                       ;AL = LOWER PART SAMPLELENGTH
  290.            out     dx,al
  291.            WAITWRITE
  292.            mov     al,ch                       ;AL = HIGHER PART SAMPLELENGTH
  293.            out     dx,al
  294.  
  295. ; TRANSFER STARTS ....... NOW ..... :)
  296.  
  297. waitloop:
  298.            mov     ah,01                       ;AH = Check for character function
  299.            int     016h                        ;   Interrupt: Keyboard
  300.            jnz     DMAstop
  301.            cmp     [ready],0                   ; check if sound sent
  302.            jz      waitloop
  303.  
  304. exit:      ; RESTORE PIC MASK
  305.            in      al,021h
  306.            or      al,PICORMASK                ;<-- SET REGISTER MASK BITS TO DISABLE
  307.            out     021h,al
  308.  
  309.            ; RESTORE IRQ :
  310.            xor     ax,ax
  311.            mov     es,ax                       ; es to page 0 (Interrupt table)
  312.            mov     si,IRQ7*4
  313.            mov     ax,[OLDInterruptOFS]
  314.            mov     es:[si],ax                  ; set old interrupt routine
  315.            mov     ax,[OLDInterruptSEG]
  316.            mov     es:[si+2],ax
  317.  
  318.            ; CLEAR KEYBUFFER
  319.            mov     ah,01                       ;AH = Check for character function
  320.            int     16h                         ;   Interrupt: Keyboard
  321.            jz      return2dos
  322.            xor     ah,ah                       ;Read character, flush keypress
  323.            int     016h                        ;   Interrupt: Keyboard
  324.  
  325.            ; TERMINATE EXE:
  326. return2dos:
  327.            mov     ax,04c00h
  328.            int     21h
  329.  
  330. ; display information if Soundblaster is not on this baseaddress
  331. RESET_ERROR:
  332.            mov     dx,offset sberror
  333.            mov     ah,9
  334.            int     21h                         ; text output
  335.            jmp     return2dos
  336.  
  337. DMAstop:
  338.            RESET_DSP
  339.            JMP     exit
  340.  
  341. ;──────────────────────────────────────────────────────────────────────────────
  342. ; Our own IRQ for detecting end of playing
  343. ; It's generated by the SoundBlaster hardware
  344. ;──────────────────────────────────────────────────────────────────────────────
  345. OWN_IRQ:   push    ax
  346.            push    dx
  347.            push    ds
  348.            mov     dx,BASEADDR+00Eh            ;DX = DSP DATA AVAILABLE (IRQ ACKNOWLEDGE)
  349.            in      al,dx
  350.            mov     ax,@DATA
  351.            mov     ds,ax                       ;change DS to data segment - to make sure that we write to the right adress
  352.            mov     [READY],1
  353.            mov     al,020h
  354.            out     020h,al                     ;ACKNOWLEDGE HARDWARE INTERRUPT
  355.            pop     ds
  356.            pop     dx
  357.            pop     ax
  358.            IRET
  359.  
  360. END     __start
  361.